package net.cyan.commons.pool.database;

import net.cyan.commons.aop.proxy.*;
import net.cyan.commons.util.ExceptionUtils;

import java.lang.reflect.Constructor;
import java.sql.*;

/**
 * 
 * @author camel
 * @date 2008-6-16
 */
public abstract class PoolCallableStatement extends PoolPreparedStatement implements CallableStatement
{
    private static Constructor<? extends PoolCallableStatement> callableStatementConstructor;

    static
    {
        try
        {
            ClassProxy proxy = new ClassProxy();
            proxy.setMethodProxys(new DelegateProxy("getCallableStatement()"));
            Class<? extends PoolCallableStatement> callableStatementClass =
                    proxy.generateClass(PoolCallableStatement.class);
            callableStatementConstructor =
                    callableStatementClass.getConstructor(CallableStatement.class, String.class, PoolConnection.class);
            callableStatementConstructor.setAccessible(true);
        }
        catch (Exception ex)
        {
            ExceptionUtils.wrapException(ex);
        }
    }

    public PoolCallableStatement(CallableStatement statement, String sql, PoolConnection connection)
    {
        super(statement, sql, connection);
    }

    protected final CallableStatement getCallableStatement()
    {
        return (CallableStatement) statement;
    }

    final CallableStatement newStatement() throws SQLException
    {
        connection.setLastSql(sql);
        return connection.getConnection()
                .prepareCall(sql, statement.getResultSetType(), statement.getResultSetConcurrency());
    }

    public static PoolCallableStatement createStatement(CallableStatement statement, String sql,
                                                        PoolConnection connection)
    {
        try
        {
            connection.addStatement(statement);
            return callableStatementConstructor.newInstance(statement, sql, connection);
        }
        catch (Exception ex)
        {
            ExceptionUtils.wrapException(ex);
        }

        return null;
    }
}